package simulateOS.management.process;

import javafx.application.Platform;
import simulateOS.controller.ProcessPageController;
import simulateOS.entity.Process;
import simulateOS.entity.*;
import simulateOS.management.device.DeviceManager;
import simulateOS.management.memory.MemoryManager;

import java.util.List;

public class ProcessRunner extends Process{
//    private File file;

    private List<ExecuteData> executeDataList;

    private int runIndex = 0;//执行到第几条语句

    //用来显示进度条
    private int dataNum = 0;

    //是否需要设备，由于判断等待设备阻塞与等待就绪队列空闲位置的阻塞

    private TimeRunner timeRunner;

    private int block_time = 0;

    private int block_all_time = 0;

    private boolean needDevice = false;
    //申请设备失败时记录的所需设备
    private String targetDeviceName = "";

    private ProcessPageController processPageController;

    private DeviceManager deviceManager;

    private MemoryManager memoryManager;

    private ProcessManager processManager;


    public ProcessRunner(File file) {
        //PCB在调用的时候设定，防止重复
//        this.file = file;
        this.executeDataList = FAT.getFAT().analyseExecutableFile(file);
    }


    public int runStr() {
        // 开始运行 开始从就绪态到运行态的动画
        this.setStatus(Status.RUN);
        processPageController.startReady2RunAnimation(this);

        if(runIndex==executeDataList.size()) {
            processManager.destroyProcess(this);
            return 0;
        }
        ExecuteData executeData = executeDataList.get(runIndex++);

        //更新进度条
        Platform.runLater(new Runnable() {
            @Override
            public void run() {
                setProgressBarValue((double)runIndex/dataNum);
            }
        });


        int type = executeData.ExecuteDataType();
        switch (type) {
            case 1:
                System.out.print("id:"+getPcb().getPid()+"  x=");
                setRunResult(executeData.getNum());
                System.out.println(getRunResult());
                return 1;
            case 2:
                System.out.print("id:"+getPcb().getPid()+"  x=");
                setRunResult((getRunResult()+1));
                System.out.println(getRunResult());
                return 1;
            case 3:
                System.out.print("id:"+getPcb().getPid()+"  x=");
                setRunResult((getRunResult()-1));
                System.out.println(getRunResult());
                return 1;
            case 4:
                //申请设备A,时间num
                block_all_time = executeData.getNum();
                applyDevice("A");
                return 0;
            case 5:
                //申请设备B
                block_all_time = executeData.getNum();
                applyDevice("B");
                return 0;
            case 6:
                //申请设备C
                block_all_time = executeData.getNum();
                applyDevice("C");
                return 0;
            default:
                //报错，释放内存
                processManager.destroyProcess(this);
                return 0;

        }
    }

    public void applyDevice(String deviceName) {

        // 播放从运行态到阻塞态的动画
        setStatus(Status.BLOCK);
        processPageController.startRun2BlockAnimation();

        processPageController.getBlockingProcessList().add(this);
        processPageController.getReadyProcessList().remove(this);

        needDevice = true;


        Device device = deviceManager.applyDevice(deviceName,this.getPcb().getPid());
        if(device.getDeviceId()==-1) {
            //申请设备失败，设备已满

            this.setStatus(Status.WAIT);    //等待型阻塞态
            this.setDevice(Device.DEFAULT_DEVICE);
            this.setTargetDeviceName(deviceName);
            return;//申请失败
        }
        this.setDevice(device);
        return;//申请成功
    }

    public boolean waitDevice() {
        Device device = deviceManager.applyDevice(targetDeviceName,getPcb().getPid());
        if(device.getDeviceId()==-1) {
            //申请设备失败，设备已满
            setStatus(Status.WAIT);    //等待型阻塞态
            return false;
        }
        setStatus(Status.BLOCK);
        setDevice(device);
        return true;
    }

    public void runDevice(Double now_time) {
        block_time++;
        if(block_time>=block_all_time) {
            retrieveDevice();
            goToWaiting();
        }
    }

    public void retrieveDevice() {
        this.setNeedDevice(false);
        Device device = this.getDevice();
        deviceManager.retrieveDevice(device);
        this.setDevice(Device.DEFAULT_DEVICE);
    }

    public void goToWaiting() {
        this.setStatus(Status.WAIT);
        this.setNeedDevice(false);
        block_time = 0;
        block_all_time = 0;
        targetDeviceName = "";
    }

    // 阻塞进程 进入 就绪队列
    public void goToReady() {
        processPageController.startBlock2ReadyAnimation();

        this.setStatus(Status.READY);
        processPageController.getReadyProcessList().add(this);
        processPageController.getBlockingProcessList().remove(this);
    }


    public void retDevice() {
        this.needDevice = false;
    }

    public boolean isNeedDevice() {
        return needDevice;
    }

    public TimeRunner getTimeRunner() {
        return timeRunner;
    }


    public void setExecuteDataList(List<ExecuteData> executeDataList) {
        this.executeDataList = executeDataList;
    }

    public void setRunIndex(int runIndex) {
        this.runIndex = runIndex;
    }

    public void setDataNum(int dataNum) {
        this.dataNum = dataNum;
    }

    public void setNeedDevice(boolean needDevice) {
        this.needDevice = needDevice;
    }


    public void setTimeRunner(TimeRunner timeRunner) {
        this.timeRunner = timeRunner;
    }

    public void setMemoryManager(MemoryManager memoryManager) {
        this.memoryManager = memoryManager;
    }

    public void setProcessManager(ProcessManager processManager) {
        this.processManager = processManager;
    }

    public String getTargetDeviceName() {
        return targetDeviceName;
    }

    public void setTargetDeviceName(String targetDeviceName) {
        this.targetDeviceName = targetDeviceName;
    }

    public void setDeviceManager(DeviceManager deviceManager) {
        this.deviceManager = deviceManager;
    }

    public void setProcessPageController(ProcessPageController processPageController) {
        this.processPageController = processPageController;
    }
}
